package com.example.tetris

import android.graphics.Paint
import android.util.Log
import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp

import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.tetris.logic.GameViewModel
import com.example.tetris.logic.NextMatrix
import com.example.tetris.logic.model.Brick
import com.example.tetris.logic.model.GameStatus
import com.example.tetris.logic.model.Spirit
import com.example.tetris.ui.ScoreboardScreen.GameScoreboard
import com.example.tetris.ui.theme.BrickMatrix
import com.example.tetris.ui.theme.BrickSpirit
import com.example.tetris.ui.theme.ScreenBackground
import java.lang.Float.min


fun DrawScope.drawText(
    matrix: Pair<Int, Int>,
    brickSize: Float,
    gameStatus: GameStatus,
    alpha: Float
) {
    val center = Offset(matrix.first * brickSize / 2, matrix.second * brickSize / 2)

    val drawText = { text: String, size: Float ->
//        kt的canvas没有drawText
        drawIntoCanvas {
            it.nativeCanvas.drawText(
                text, center.x, center.y,
                Paint().apply {
                    color = Color.Black.copy(alpha = alpha).toArgb()
                    textSize = size
                    textAlign = Paint.Align.CENTER
                    style = Paint.Style.FILL_AND_STROKE
                    strokeWidth = size / 12
                }
            )
        }
    }

    if (gameStatus == GameStatus.Onboard) {
        drawText("TETRIS", 80f)
    } else if (gameStatus == GameStatus.GameOver) {
        drawText("GAME OVER", 60f)
    }
}

fun DrawScope.drawMatrixBorder(brickSize: Float, matrix: Pair<Int, Int>) {
    val gap = brickSize * matrix.first * 0.05f

    drawRect(
        Color.Black,
        topLeft = Offset(-gap / 2, -gap / 2),
        size = Size(
            width = matrix.first * brickSize + gap,
            height = matrix.second * brickSize + gap
        ),
        style = Stroke(width = 1.dp.toPx())
    )

}


fun DrawScope.drawBricks(list: List<Brick>, brickSize: Float, matrix: Pair<Int, Int>) {
    clipRect(0f, 0f, matrix.first * brickSize, matrix.second * brickSize) {
        list.forEach {
            drawBrick(brickSize, it.location, BrickSpirit)
        }
    }
}

fun DrawScope.drawBrick(brick: Float, offset: Offset, color: Color) {
    val actualLocation = Offset(x = offset.x * brick, y = offset.y * brick)
    val outerSize = brick * 0.8f
    val outerOffset = (brick - outerSize) / 2

//    val actualLocation = Offset(x = offset.x * brick, y = offset.y * brick)

    drawRect(
        color = color,
        topLeft = actualLocation + Offset(outerOffset, outerOffset),
        size = Size(width = outerSize, height = outerSize),
        style = Stroke(outerSize / 10)
    )

    val innerSize = outerSize * 0.5f
    val innerOffset = (brick - innerSize) / 2

    drawRect(
        color = color,
        topLeft = actualLocation + Offset(innerOffset, innerOffset),
        size = Size(width = innerSize, height = innerSize),
    )
}

fun DrawScope.drawMatrix(brickSize: Float, matrix: Pair<Int, Int>) {
    for (i in 0 until matrix.first) {
        for (j in 0 until matrix.second) {
            drawBrick(brickSize, Offset(i.toFloat(), j.toFloat()), BrickMatrix)
        }
    }
}

fun DrawScope.drawSpirit(spirit: Spirit, brickSize: Float, matrix: Pair<Int, Int>) {
    if (matrix == NextMatrix) {
        Log.d("drawSpirit", "drawSpirit: ${spirit.location}")
    }
    clipRect(0f, 0f, matrix.first * brickSize, matrix.second * brickSize) {
        spirit.location.forEach {
            drawBrick(brickSize, Offset(it.x, it.y), BrickSpirit)
        }
    }
}

@Composable
fun GameScreen(modifier: Modifier = Modifier) {
    val viewModel = viewModel<GameViewModel>()
    val viewState = viewModel.viewState.value

    Box(
        modifier
            .background(Color.Black)
            .padding(1.dp)
            .background(ScreenBackground)
            .padding(10.dp)
    ) {


        val animateValue by rememberInfiniteTransition().animateFloat(
            initialValue = 0f,
            targetValue = 0.7f,
            animationSpec = infiniteRepeatable(
                animation = tween(1500),
                repeatMode = RepeatMode.Reverse

            )
        )

        Canvas(modifier = Modifier.fillMaxSize()) {
            val brickSize: Float =
                min(size.width / viewState.matrix.first, size.height / viewState.matrix.second)

            drawMatrix(brickSize, viewState.matrix)
            drawMatrixBorder(brickSize, viewState.matrix)
            drawBricks(viewState.bricks, brickSize, viewState.matrix)
            drawSpirit(viewState.spirit, brickSize, viewState.matrix)
            drawText(matrix = viewState.matrix, brickSize, viewState.gameStatus, animateValue)

        }

        GameScoreboard(
            spirit = run {
                if (viewState.spirit == Spirit.Empty) Spirit.Empty
                else viewState.spiritNext.rotate()
            },
            score = viewState.score,
            level = viewState.level,
            isPaused = viewState.isPause,
            isMute = viewState.isMute,
            line = viewState.line

        )
    }
}